package com.cug.campus_sh_market_server.util;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.util.StringUtils;

import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * @Author sxt
 * @Date 2020.04.05
 */
public class QueryWrapperUtil {
    /**
     * 封装查询wrapper
     *
     * @param targetType QueryWrapper的目标类型
     * @param paramClass 参数类型
     * @param param      参数对象
     * @param <T>        QueryWrapper的目标类类型
     * @param <E>        参数类类型
     * @return {@link QueryWrapper}
     */
    public static <T, E> QueryWrapper<T> getQueryWrapper(Class<T> targetType, Class<E> paramClass, E param) {
        if (targetType == null || paramClass == null || param == null) {
            return null;
        }
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        Method[] declaredMethods = paramClass.getDeclaredMethods();
        Stream<Method> getMethods = Arrays.stream(declaredMethods).filter(item -> item.getName().startsWith("get"));
        // 需要or查询的条件后续单独处理
        List<String> orField = new ArrayList<>();
        getMethods.forEach(item -> {
            String methodName = item.getName();
            String tmp = methodName.substring(methodName.indexOf("get") + "get".length());
            String fieldName = tmp.substring(0, 1).toLowerCase() + tmp.substring(1);/*首字母转小写*/
            String column = getColumn(paramClass, fieldName);
            if (column != null) {
                Object rs = null;
                try {
                    rs = item.invoke(param);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
                if (!StringUtils.isEmpty(rs)) {
                    if (!isFieldHasAnnotation(fieldName, paramClass, OrSelect.class)) {
                        if (isFieldHasAnnotation(fieldName, paramClass, NeedLike.class)) {
                            queryWrapper.like(column, rs);
                        } else {
                            queryWrapper.eq(column, rs);
                        }
                    } else {
                        orField.add(fieldName);
                    }
                }
            }
        });
        if (!orField.isEmpty()) {
            queryWrapper.and(tQueryWrapper -> {
                // 处理or列条件
                orField.forEach(fieldName -> {
                    String column = getColumn(paramClass, fieldName);
                    if (column != null) {
                        Object rs = null;
                        try {
                            Field field = paramClass.getDeclaredField(column);
                            field.setAccessible(true);
                            rs = field.get(param);
                        } catch (NoSuchFieldException | IllegalAccessException e) {
                            e.printStackTrace();
                        }
                        if (!StringUtils.isEmpty(rs)) {
                            if (isFieldHasAnnotation(fieldName, paramClass, NeedLike.class)) {
                                tQueryWrapper.or().like(column, rs);
                            } else {
                                tQueryWrapper.or().eq(column, rs);
                            }
                        }
                    }

                });
            });
        }

        return queryWrapper;
    }

    /**
     * @param paramClass 需要解析的类
     * @param fieldName  属性名称
     * @param <E>        需要解析的类类型
     * @return 字段对应的column名
     */
    private static <E> String getColumn(Class<E> paramClass, String fieldName) {
        if (isFieldHasAnnotation(fieldName, paramClass, Ignore.class)) {
            return null;
        }
        String column = null;
        Field field = null;
        try {
            field = paramClass.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        if (field != null) {
            Column annotation = field.getAnnotation(Column.class);
            if (annotation != null) {
                column = annotation.column();
            } else {
                column = UnderlineWithHump.HumpToUnderline(fieldName);
            }
        }
        return column;
    }

    /**
     * 判断一个类的字段是否标有某个特定的注解
     *
     * @param fieldName   字段名
     * @param tClass      目标检测类
     * @param tAnnotation 目标检测注解类
     * @return 布尔值
     */
    private static <T, E extends Annotation> boolean isFieldHasAnnotation(String fieldName, Class<T> tClass, Class<E> tAnnotation) {
        Field targetField = null;
        try {
            targetField = tClass.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            return false;
        }
        E needLike = (E) targetField.getAnnotation(tAnnotation);

        return needLike != null;
    }


    /**
     * 用来标记是否需要使用Like关键字
     */
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface NeedLike {

    }

    /**
     * 用来标记是否需要使用OR查询
     * 标记时至少类中有两个以上字段时有效
     */
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface OrSelect {

    }

    /**
     * 用来标记column的名字
     */
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Column {
        String column() default "";
    }

    /**
     * 用来标记是否需要忽略
     */
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Ignore {

    }
}
